package linear_ist

import (
	"errors"
	"strconv"
	"strings"
)

type Node struct {
	data int
	next *Node
}

type SinglyLinkedList struct {
	head *Node
}

func CreateSinglyLinkedList() *SinglyLinkedList {
	return &SinglyLinkedList{nil}
}

func (list *SinglyLinkedList) Append(data int) {
	node := &Node{data, nil}
	pre := list.head
	if pre == nil {
		// 空链表
		list.head = node
		return
	}
	// 找到最后一个节点
	for pre.next != nil {
		pre = pre.next
	}
	pre.next = node
	return
}

func (list *SinglyLinkedList) Reversal() {

}

func (list *SinglyLinkedList) Get(index int) (int, error) {
	node := list.getNode(index)
	if node == nil {
		return -1, errors.New("无此节点")
	}
	return node.data, nil
}

func (list *SinglyLinkedList) getNode(index int) *Node {
	node := list.head
	for i := 0; node != nil; i++ {
		if i == index {
			return node
		}
		node = node.next
	}
	return nil
}

func (list *SinglyLinkedList) Insert(index int, data int) error {
	index -= 1
	if index < 0 {
		// 插入首节点
		list.InsertToFirst(data)
		return nil
	}
	pre := list.getNode(index)
	if pre == nil {
		return errors.New("无此节点")
	}
	node := &Node{data, pre.next}
	pre.next = node
	return nil
}

func (list *SinglyLinkedList) Clear() {
	node := list.head
	list.head = nil
	var temp *Node
	for node != nil {
		temp = node.next
		node.next = nil
		node = temp
	}
}

func (list *SinglyLinkedList) Delete(index int) error {
	index -= 1
	if index < 0 {
		// 删除首节点
		list.DeleteFirst()
		return nil
	}
	prevNode := list.getNode(index)
	if prevNode == nil {
		return errors.New("无此节点")
	}
	thisNode := prevNode.next
	if thisNode == nil {
		return nil
	}
	nextNode := thisNode.next
	prevNode.next = nextNode
	return nil
}

func (list *SinglyLinkedList) DeleteFirst() {
	head := list.head
	if head == nil {
		return
	}
	next := head.next
	list.head = next
}

func (list *SinglyLinkedList) InsertToFirst(data int) {
	list.head = &Node{data, list.head}
}

func (list *SinglyLinkedList) ToString() string {
	var build strings.Builder
	node := list.head
	for node != nil {
		build.WriteString(strconv.Itoa(node.data))
		build.WriteString(" -> ")
		node = node.next
	}
	build.WriteString("nul")
	return build.String()
}
